#include "worker.h"

Worker::Worker()
{
	this->_flags = 0;
	this->_arguments = ArgumentList();

	return;
}

Worker::Worker(TaskFunc function)
{
	this->_flags = 0;
	this->_arguments = ArgumentList();
	
	this->setProcess(function);

	return;
}

void Worker::addArgument(int ArgumentId, void *value)
{
	this->delArgument(ArgumentId);

	this->_arguments.insert(ArgumentItem(ArgumentId, value));

	return;
}

template<class T> T *Worker::getArgument(int ArgumentId)
{
	ArgumentIter it = this->_arguments.find(ArgumentId);

	if (it == this->_arguments.end())
	{
		return NULL;
	}

	return (T *)it->second;
}

void Worker::delArgument(int ArgumentId)
{
	ArgumentIter it;

	if ((it = this->_arguments.find(ArgumentId)) != this->_arguments.end())
	{
		this->_arguments.erase(it);
	}

	return;
}

void Worker::setFlags(int flags)
{
	this->_flags = flags;
}

void Worker::setProcess(TaskFunc *function)
{
	this->_function = function;
}

bool Worker::start()
{
	LPVOID *arguments = new LPVOID;
	
	for (ArgumentIter it = this->_arguments.begin(); it != this->_arguments.end(); ++it)
	{
		arguments[it->first] = (LPVOID *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(it->second));
		arguments[it->first] = it->second;
	}

	this->_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) this->_function, arguments, this->_flags, &this->_threadId);

	if (this->_thread == NULL)
	{
		ExitProcess(EXIT_FAILURE);

		return false;
	}

	return true;
}

bool Worker::terminate()
{
	if (!TerminateProcess(this->_thread, EXIT_SUCCESS))
	{
		return false;
	}

	if (!CloseHandle(this->_thread))
	{
		return false;
	}

	for (ArgumentIter it = this->_arguments.begin(); it != this->_arguments.end(); ++it)
	{
		HeapFree(GetProcessHeap(), 0, it->second);
	}

	return true;
}

bool Worker::terminate(bool wait)
{
	if (wait)
	{
		if (WaitForSingleObject(this->_thread, INFINITE) != WAIT_FAILED)
		{
			this->terminate();
		}

		this->terminate();
	}
	else
	{
		return this->terminate();
	}

	return true;
}



